Modifying Original file (Fig2_ExtFig4_WT_RPM_Organoids_Allografts_Final.R) into an executable RMarkdown Notebook

Load RPM Organoids data

RPM_Orgs <- readRDS("../data/05_2025_RPM_Orgs_Only_ExtFig4a-c.rds")

Load CellTagged Organoid Allografts data

RPM_Orgs_Allo <- readRDS("../data/05_2025_RPM_Orgs_Allo_Fig2d.rds")

Load RPM allograft-only data

RPM_Allo <- readRDS("../data/05_2025_RPM_AllograftOnly_Fig2e.rds")

Load RPM allografts as SingleCellExperiment

sce <- readRDS('../data/RPM_Allo_only_sce.rds')

UMAP Plots

Fig 1i

DimPlot(RPM_Orgs_Allo,  group.by='Sample',cols=sample_cols, reduction='umap',
        label=FALSE, label.size=6, shuffle=TRUE, pt.size=0.01) & NoAxes()

FeaturePlot(RPM_Orgs_Allo, features = c("NE_Consensus1"), 
            pt.size=0.2, reduction='umap', order=TRUE) + 
    ggplot2::scale_color_gradientn(colors=rocket(10, direction=-1)) & NoAxes()


FeaturePlot(RPM_Orgs_Allo, features = c("Basal_Consensus1"), 
            pt.size=0.2, reduction='umap',order=TRUE) + 
    ggplot2::scale_color_gradientn(colors=rocket(10, direction=-1)) & NoAxes()

Fig 1j

Violin plots of expression of TFs by Leiden cluster

genes <- c("Ascl1","Neurod1","Pou2f3","Atoh1","Yap1","Trp63")

# Create violin plots with Kruskal-Wallis test
plots <- lapply(genes, function(gene) {
  p <- VlnPlot(RPM_Orgs_Allo,
               features = gene,
               group.by = "leiden_scVI_1.3",
               cols = my_colors,
               alpha = 0.5) +  # smaller dots
    ggpubr::stat_compare_means(method = "kruskal.test", 
                       label = "p.format", 
                       label.x = 2,size = 5) +
    ggtitle("") +
    theme(plot.title = element_text(face = "italic"), legend.position = "none",  # Remove legend
          axis.title.x = element_blank(),axis.title.y = element_text(size = 20),
          axis.text.y = element_text(size = 20), axis.text.x = element_text(size = 14)) +  # Remove x-axis label
    labs(y = "Expression")  # Change y-axis label to "Expression"
  return(p)
})

# Arrange plots
patchwork::wrap_plots(plots, ncol = 6)

UMAP Plots by Sample and Cluster

Extended Data Fig 4a

DimPlot(RPM_Orgs, group.by='Genotype', cols=c("darkorchid4","orange"), reduction='umap',
        label=FALSE, label.size=6, shuffle=TRUE) & NoAxes()


DimPlot(RPM_Orgs, group.by='cluster', cols=colors_figED4a, reduction='umap',
        label=TRUE, label.size=10) & NoAxes()

Extended Data Fig 4c

DimPlot(RPM_Orgs, reduction = "umap", group.by = "Phase",
        shuffle=TRUE, label=FALSE, pt.size=.05, 
        cols=c("indianred3","green3","royalblue4")) + NoAxes()

Ext. Data Fig. 4d

DimPlot(RPM_Orgs_Allo, reduction = "umap", group.by = "Phase",
        shuffle=TRUE, label=FALSE, pt.size=.05, 
        cols=c("indianred3","green3","royalblue4")) + NoAxes()

# Plot barplot for Ext. Data Fig. 4d #
##### What % of cells per phase in each group? ####
x <- table(Idents(RPM_Orgs_Allo),RPM_Orgs_Allo@meta.data$Phase)
proportions <- as.data.frame(100*prop.table(x, margin = 1))

colnames(proportions)<-c("Cluster", "Sample", "Frequency")

# ggbarplot(proportions, x="Sample", y="Frequency", fill = "Sample", group = "Sample", ylab = "Frequency (percent)", xlab="Phase", palette =c("indianred3","green3","royalblue4"))+ theme_bw()+ facet_wrap(facets = "Cluster", scales="free_y", ncol =4)+ theme(axis.text.y = element_text(size=12)) +rotate_x_text(angle = 45)

# Stacked
p<-ggplot(proportions, aes(fill=Sample, y=Frequency, x=Cluster)) +
  geom_bar(position="stack", stat="identity")

p + scale_fill_manual(values=c("indianred3","green3","royalblue4")) + 
    theme_bw() + 
    theme(axis.text.y = element_text(size=20), axis.text.x=element_text(size=20,angle=45, hjust = 1), 
          axis.title.x = element_text(size=20), axis.title.y = element_text(size=20), 
          legend.text = element_text(size=20), legend.title = element_text(size=20)) +
    labs(x=NULL, y="Frequency (%)", fill=NULL)

Fig 1j

DimPlot(RPM_Allo, group.by='leiden_scVI_1.3', cols=my_colors,
        reduction='umap', label=TRUE, label.size=7) & NoAxes() + theme(legend.position="none")

UMAP by Fate

Fig. 1k

pheno_col<-c("brown2","darkorchid4","dodgerblue","#66A61E","orange","turquoise4")

DimPlot(RPM_Allo, group.by=c("Pheno"), cols=pheno_col, shuffle=TRUE, pt.size=0.6)+NoAxes()

Fig 1l

# Fig 2g plots #
FeaturePlot(RPM_Allo, features = c("NE_spearman"), pt.size=0.2, 
            reduction='umap', order=TRUE) + 
    scale_color_viridis(option="rocket",direction=-1) & NoAxes()

Violin plots of Archetypes by leiden cluster

Ext. Data Fig. 4f

VlnPlot(
  RPM_Allo,
  features = c("A_Archetype1","A2_Archetype1","N_Archetype1","P_Archetype1"),
  group.by = "leiden_scVI_1.3",
  cols = my_colors,
  alpha = 0.7,
  ncol = 2
) & 
  theme(
    axis.text.x = element_text(size = 8),                # smaller x-axis labels
    plot.title = element_text(face = "bold", size=0),          # italicize titles
    axis.title.x = element_text(size = 24),              # optional size tweaks
    axis.title.y = element_text(size = 24)
  ) &
  labs(
    y = "Expression",
    x = "Cluster"
  )

Plot Signature Scores by Phenotype

phenotypes <- as.character(unique(RPM_Allo$Pheno))
pheno_pairs_list <- combn(phenotypes, 2, simplify = FALSE)

Define function to plot violin plots by phenotype

plotVlnByPhen <- function(feature, yl=c(-0.1,0.3), focus=NA) {
    if(!is.na(focus)) {
        pheno_pairs_list <- pheno_pairs_list[sapply(pheno_pairs_list, function(x) focus %in% x)]
    }
    
    scater::plotColData(sce, x = "Pheno", y = feature, colour_by = "Pheno") + 
        scale_discrete_manual(aesthetics = c("colour", "fill"), values=pheno_col) +
        theme(axis.title.y = element_text(size = 24), axis.text.y = element_text(size = 16),
              axis.text.x = element_blank(),   # rotate x-axis labels
              plot.title = element_blank(),    # remove plot title
              legend.position = "none"         # remove legend
        ) + labs(x = "",                     # custom x-axis title
                 y = "Signature score"        # custom y-axis title
        ) + ylim(yl[1], yl[2]) + 
        geom_boxplot(fill=pheno_col, alpha=1/5, position = position_dodge(width = .2),
                     size=0.2, color="black", notch=TRUE, notchwidth=0.3, outlier.shape = 2, outlier.colour=NA) #   + 
        # stat_summary(fun = mean,
        #              geom = "point",
        #              shape = 18,
        #              size = 2,
        #              color = "red",
        #              position = position_dodge(width = 0.5)) + 
        # ggpubr::stat_compare_means(method = "wilcox.test", label = "p.signif", size=4, 
        #                            vjust = 0.5,
        #                            hide.ns = TRUE, comparisons = pheno_pairs_list)
}

Fig 1l

NE correlation

plotVlnByPhen("NE_spearman", yl=c(-.75, .8), focus="NE")

Fig 1m

SCLC cell type consensus signature scores * NE cell * Tuft cell * Basal cell

plotVlnByPhen("NE_Consensus1", yl=c(-0.5, 1))

plotVlnByPhen("Tuft_Consensus1", yl=c(-0.1, 0.5))

plotVlnByPhen("Basal_Consensus1", yl=c(-0.1, 1.1))

Fig 1n

TF target gene scores * ASCL1 targets * NEUROD1 targets * ATOH1 targets * POU2F3 targets * YAP1 activity score

plotVlnByPhen("ASCL1_Targets1", yl=c(-0.1,0.6))

plotVlnByPhen("NEUROD1_Targets1", yl=c(-0.1,0.25))

plotVlnByPhen("ATOH1_Targets1", yl=c(-0.1,.3))

plotVlnByPhen("POU2F3_Targets1", yl=c(-0.1, 0.22))

plotVlnByPhen("YAP1_Activity_Score1", yl=c(-0.1, 1))

LS0tCnRpdGxlOiAiV1QgUlBNIE9yZ2Fub2lkcyBBbGxvZ3JhZnRzIE5vdGVib29rIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZGF0ZTogMjAyNS0wNi0xNgphdXRob3I6ICJBYmJpZSBJcmVsYW5kLCBEYXJyZW4gVHlzb24iCi0tLQoKTW9kaWZ5aW5nIFtPcmlnaW5hbCBmaWxlIChGaWcyX0V4dEZpZzRfV1RfUlBNX09yZ2Fub2lkc19BbGxvZ3JhZnRzX0ZpbmFsLlIpXShQcmVwcm9jZXNzaW5nX2Zvcl9yZWZlcmVuY2UvUl9Db2RlL0ZpZzJfRXh0RmlnNF9XVF9SUE1fT3JnYW5vaWRzX0FsbG9ncmFmdHNfRmluYWwuUikgaW50byBhbiBleGVjdXRhYmxlIFJNYXJrZG93biBOb3RlYm9vawoKIyMjIFJlbGF0ZWQgdG86CiogRmlnIDFpLW4KKiBFeHRlbmRlZCBEYXRhIEZpZyA0YS1mCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICAgIGxpYnJhcnkodmlyaWRpcykKICAgIGxpYnJhcnkoZ2dwbG90MikKICAgIGxpYnJhcnkoc2NhdGVyKQogICAgbGlicmFyeShTZXVyYXQpCiAgICBsaWJyYXJ5KGdncHVicikKfSkKYGBgCgojIyMjIERlZmluZSBjb2xvcnMgZm9yIGZpZ3VyZXMKYGBge3J9CiMgRGVmaW5lIGNvbG9yIHNjaGVtZSBhbmQgcGxvdCBVTUFQIGFzIGluIEZpZy4gMmUgIwpteV9jb2xvcnMgPC0gYygKICAiI0U0MUExQyIsICMgc3Ryb25nIHJlZAogICIjMzc3RUI4IiwgIyBtZWRpdW0gYmx1ZQogICIjNERBRjRBIiwgIyBncmVlbgogICIjOTg0RUEzIiwgIyBwdXJwbGUKICAiI0ZGN0YwMCIsICMgb3JhbmdlCiAgIiNGRkZGMzMiLCAjIHllbGxvdwogICIjQTY1NjI4IiwgIyBicm93bgogICIjZTcyOThhIiwgIyBwaW5rCiAgIiM2NjY2NjYiLCAjIGdyZXkKICAibGF2ZW5kZXIiLCAjIHRlYWwKICAiI0ZDOEQ2MiIsICMgc2FsbW9uCiAgIiM4REEwQ0IiLCAjIHNvZnQgYmx1ZQogICIjRTc4QUMzIiwgIyBzb2Z0IHBpbmsgKGRpZmZlcmVudCBmcm9tIDgpCiAgIiNBNkQ4NTQiLCAjIGxpZ2h0IGdyZWVuIChidXQgeWVsbG93aXNoIHRpbnQsIG5vdCBncmVlbikKICAiI0ZGRDkyRiIsICMgbGVtb24geWVsbG93CiAgIiNFNUM0OTQiLCAjIGxpZ2h0IGJyb3duCiAgIiNCM0IzQjMiLCAjIGxpZ2h0IGdyZXkKICAiIzFCOUU3NyIsICMgZGVlcCB0ZWFsCiAgIiNEOTVGMDIiLCAjIGRhcmsgb3JhbmdlCiAgIiM3NTcwQjMiLCAjIHN0cm9uZyBwdXJwbGUKICAidHVycXVvaXNlIiAgIyBvbGl2ZSBncmVlbiAoTk9UIHNhbWUgZ3JlZW4gYXMgYmVmb3JlKQopCgpjb2xvcnNfZmlnRUQ0YSA8LSBjKCdkZWVwc2t5Ymx1ZTQnLCAnI0ZDOEQ2MicsJyMyY2EwMmMnLCAnYnJvd24xJywgJ3B1cnBsZScsICcjQTA1MjJEJywKICAgICAgICAgICAgICAgICAgICAncGluazInLCAgJyNhMWMyOTknLCAgJyMwYWE2ZDgnLCAnbGlnaHRibHVlJywnc2FsbW9uMScsJ2xpZ2h0Z3JlZW4nKQoKc2FtcGxlX2NvbHM8LWMoIm9yYW5nZSIsIiNEOEJGRDgiLCJkYXJrb3JjaGlkNCIsICMgZGVlcCB0ZWFsCiAgICAgICAgICAgICAgICJ0dXJxdW9pc2UiLCAiIzFCOUU3NyIgIyBkYXJrIG9yYW5nZQopCgpwaGVub19jb2w8LWMoImJyb3duMiIsImRhcmtvcmNoaWQ0IiwiZG9kZ2VyYmx1ZSIsIiM2NkE2MUUiLCJvcmFuZ2UiLCJ0dXJxdW9pc2U0IikKCmBgYAoKCiMjIyBMb2FkIFJQTSBPcmdhbm9pZHMgZGF0YQpgYGB7cn0KUlBNX09yZ3MgPC0gcmVhZFJEUygiLi4vZGF0YS8wNV8yMDI1X1JQTV9PcmdzX09ubHlfRXh0RmlnNGEtYy5yZHMiKQpgYGAKCiMjIyBMb2FkIENlbGxUYWdnZWQgT3JnYW5vaWQgQWxsb2dyYWZ0cyBkYXRhCmBgYHtyfQpSUE1fT3Jnc19BbGxvIDwtIHJlYWRSRFMoIi4uL2RhdGEvMDVfMjAyNV9SUE1fT3Jnc19BbGxvX0ZpZzJkLnJkcyIpCmBgYAoKIyMjIExvYWQgUlBNIGFsbG9ncmFmdC1vbmx5IGRhdGEKYGBge3J9ClJQTV9BbGxvIDwtIHJlYWRSRFMoIi4uL2RhdGEvMDVfMjAyNV9SUE1fQWxsb2dyYWZ0T25seV9GaWcyZS5yZHMiKQpgYGAKCiMjIyBMb2FkIFJQTSBhbGxvZ3JhZnRzIGFzIFNpbmdsZUNlbGxFeHBlcmltZW50CmBgYHtyfQpzY2UgPC0gcmVhZFJEUygnLi4vZGF0YS9SUE1fQWxsb19vbmx5X3NjZS5yZHMnKQpgYGAKCgojIyMgVU1BUCBQbG90cwojIyMjICoqRmlnIDFpKioKYGBge3J9CkRpbVBsb3QoUlBNX09yZ3NfQWxsbywgIGdyb3VwLmJ5PSdTYW1wbGUnLGNvbHM9c2FtcGxlX2NvbHMsIHJlZHVjdGlvbj0ndW1hcCcsCiAgICAgICAgbGFiZWw9RkFMU0UsIGxhYmVsLnNpemU9Niwgc2h1ZmZsZT1UUlVFLCBwdC5zaXplPTAuMDEpICYgTm9BeGVzKCkKYGBgCgoKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KRmVhdHVyZVBsb3QoUlBNX09yZ3NfQWxsbywgZmVhdHVyZXMgPSBjKCJORV9Db25zZW5zdXMxIiksIAogICAgICAgICAgICBwdC5zaXplPTAuMiwgcmVkdWN0aW9uPSd1bWFwJywgb3JkZXI9VFJVRSkgKyAKICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvcnM9cm9ja2V0KDEwLCBkaXJlY3Rpb249LTEpKSAmIE5vQXhlcygpCgpGZWF0dXJlUGxvdChSUE1fT3Jnc19BbGxvLCBmZWF0dXJlcyA9IGMoIkJhc2FsX0NvbnNlbnN1czEiKSwgCiAgICAgICAgICAgIHB0LnNpemU9MC4yLCByZWR1Y3Rpb249J3VtYXAnLG9yZGVyPVRSVUUpICsgCiAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3JzPXJvY2tldCgxMCwgZGlyZWN0aW9uPS0xKSkgJiBOb0F4ZXMoKQpgYGAKIyMjIyBGaWcgMWoKVmlvbGluIHBsb3RzIG9mIGV4cHJlc3Npb24gb2YgVEZzIGJ5IExlaWRlbiBjbHVzdGVyCmBgYHtyIGZpZy5oZWlnaHQ9My41LCBmaWcud2lkdGg9MTUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdlbmVzIDwtIGMoIkFzY2wxIiwiTmV1cm9kMSIsIlBvdTJmMyIsIkF0b2gxIiwiWWFwMSIsIlRycDYzIikKCiMgQ3JlYXRlIHZpb2xpbiBwbG90cyB3aXRoIEtydXNrYWwtV2FsbGlzIHRlc3QKcGxvdHMgPC0gbGFwcGx5KGdlbmVzLCBmdW5jdGlvbihnZW5lKSB7CiAgcCA8LSBWbG5QbG90KFJQTV9PcmdzX0FsbG8sCiAgICAgICAgICAgICAgIGZlYXR1cmVzID0gZ2VuZSwKICAgICAgICAgICAgICAgZ3JvdXAuYnkgPSAibGVpZGVuX3NjVklfMS4zIiwKICAgICAgICAgICAgICAgY29scyA9IG15X2NvbG9ycywKICAgICAgICAgICAgICAgYWxwaGEgPSAwLjUpICsgICMgc21hbGxlciBkb3RzCiAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAia3J1c2thbC50ZXN0IiwgCiAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLCAKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbC54ID0gMixzaXplID0gNSkgKwogICAgZ2d0aXRsZSgiIikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gIml0YWxpYyIpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsICAjIFJlbW92ZSBsZWdlbmQKICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSxheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwKICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkpICsgICMgUmVtb3ZlIHgtYXhpcyBsYWJlbAogICAgbGFicyh5ID0gIkV4cHJlc3Npb24iKSAgIyBDaGFuZ2UgeS1heGlzIGxhYmVsIHRvICJFeHByZXNzaW9uIgogIHJldHVybihwKQp9KQoKIyBBcnJhbmdlIHBsb3RzCnBhdGNod29yazo6d3JhcF9wbG90cyhwbG90cywgbmNvbCA9IDYpCmBgYAoKCiMjIyBVTUFQIFBsb3RzIGJ5IFNhbXBsZSBhbmQgQ2x1c3RlcgojIyMjICoqRXh0ZW5kZWQgRGF0YSBGaWcgNGEqKgpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD00LjV9CkRpbVBsb3QoUlBNX09yZ3MsIGdyb3VwLmJ5PSdHZW5vdHlwZScsIGNvbHM9YygiZGFya29yY2hpZDQiLCJvcmFuZ2UiKSwgcmVkdWN0aW9uPSd1bWFwJywKICAgICAgICBsYWJlbD1GQUxTRSwgbGFiZWwuc2l6ZT02LCBzaHVmZmxlPVRSVUUpICYgTm9BeGVzKCkKYGBgCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTQuNX0KCkRpbVBsb3QoUlBNX09yZ3MsIGdyb3VwLmJ5PSdjbHVzdGVyJywgY29scz1jb2xvcnNfZmlnRUQ0YSwgcmVkdWN0aW9uPSd1bWFwJywKICAgICAgICBsYWJlbD1UUlVFLCBsYWJlbC5zaXplPTEwKSAmIE5vQXhlcygpCgpgYGAKIyMjIyAqKkV4dGVuZGVkIERhdGEgRmlnIDRjKioKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NC43NX0KRGltUGxvdChSUE1fT3JncywgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJQaGFzZSIsCiAgICAgICAgc2h1ZmZsZT1UUlVFLCBsYWJlbD1GQUxTRSwgcHQuc2l6ZT0uMDUsIAogICAgICAgIGNvbHM9YygiaW5kaWFucmVkMyIsImdyZWVuMyIsInJveWFsYmx1ZTQiKSkgKyBOb0F4ZXMoKQpgYGAKCiMjIyMgRXh0LiBEYXRhIEZpZy4gNGQgCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTV9CkRpbVBsb3QoUlBNX09yZ3NfQWxsbywgcmVkdWN0aW9uID0gInVtYXAiLCBncm91cC5ieSA9ICJQaGFzZSIsCiAgICAgICAgc2h1ZmZsZT1UUlVFLCBsYWJlbD1GQUxTRSwgcHQuc2l6ZT0uMDUsIAogICAgICAgIGNvbHM9YygiaW5kaWFucmVkMyIsImdyZWVuMyIsInJveWFsYmx1ZTQiKSkgKyBOb0F4ZXMoKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTR9CiMgUGxvdCBiYXJwbG90IGZvciBFeHQuIERhdGEgRmlnLiA0ZCAjCiMjIyMjIFdoYXQgJSBvZiBjZWxscyBwZXIgcGhhc2UgaW4gZWFjaCBncm91cD8gIyMjIwp4IDwtIHRhYmxlKElkZW50cyhSUE1fT3Jnc19BbGxvKSxSUE1fT3Jnc19BbGxvQG1ldGEuZGF0YSRQaGFzZSkKcHJvcG9ydGlvbnMgPC0gYXMuZGF0YS5mcmFtZSgxMDAqcHJvcC50YWJsZSh4LCBtYXJnaW4gPSAxKSkKCmNvbG5hbWVzKHByb3BvcnRpb25zKTwtYygiQ2x1c3RlciIsICJTYW1wbGUiLCAiRnJlcXVlbmN5IikKCiMgZ2diYXJwbG90KHByb3BvcnRpb25zLCB4PSJTYW1wbGUiLCB5PSJGcmVxdWVuY3kiLCBmaWxsID0gIlNhbXBsZSIsIGdyb3VwID0gIlNhbXBsZSIsIHlsYWIgPSAiRnJlcXVlbmN5IChwZXJjZW50KSIsIHhsYWI9IlBoYXNlIiwgcGFsZXR0ZSA9YygiaW5kaWFucmVkMyIsImdyZWVuMyIsInJveWFsYmx1ZTQiKSkrIHRoZW1lX2J3KCkrIGZhY2V0X3dyYXAoZmFjZXRzID0gIkNsdXN0ZXIiLCBzY2FsZXM9ImZyZWVfeSIsIG5jb2wgPTQpKyB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSkgK3JvdGF0ZV94X3RleHQoYW5nbGUgPSA0NSkKCiMgU3RhY2tlZApwPC1nZ3Bsb3QocHJvcG9ydGlvbnMsIGFlcyhmaWxsPVNhbXBsZSwgeT1GcmVxdWVuY3ksIHg9Q2x1c3RlcikpICsKICBnZW9tX2Jhcihwb3NpdGlvbj0ic3RhY2siLCBzdGF0PSJpZGVudGl0eSIpCgpwICsgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoImluZGlhbnJlZDMiLCJncmVlbjMiLCJyb3lhbGJsdWU0IikpICsgCiAgICB0aGVtZV9idygpICsgCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemU9MjAsYW5nbGU9NDUsIGhqdXN0ID0gMSksIAogICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIAogICAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkgKwogICAgbGFicyh4PU5VTEwsIHk9IkZyZXF1ZW5jeSAoJSkiLCBmaWxsPU5VTEwpCgpgYGAKCgoKIyMjIyBGaWcgMWoKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NX0KRGltUGxvdChSUE1fQWxsbywgZ3JvdXAuYnk9J2xlaWRlbl9zY1ZJXzEuMycsIGNvbHM9bXlfY29sb3JzLAogICAgICAgIHJlZHVjdGlvbj0ndW1hcCcsIGxhYmVsPVRSVUUsIGxhYmVsLnNpemU9NykgJiBOb0F4ZXMoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpCmBgYAoKIyMjIFVNQVAgYnkgRmF0ZQojIyMjICoqRmlnLiAxayoqCmBgYHtyIGZpZy5oZWlnaHQ9NCwgZmlnLndpZHRoPTZ9CnBoZW5vX2NvbDwtYygiYnJvd24yIiwiZGFya29yY2hpZDQiLCJkb2RnZXJibHVlIiwiIzY2QTYxRSIsIm9yYW5nZSIsInR1cnF1b2lzZTQiKQoKRGltUGxvdChSUE1fQWxsbywgZ3JvdXAuYnk9YygiUGhlbm8iKSwgY29scz1waGVub19jb2wsIHNodWZmbGU9VFJVRSwgcHQuc2l6ZT0wLjYpK05vQXhlcygpCmBgYAoKIyMjIyBGaWcgMWwKYGBge3IgZmlnLmhlaWdodD00LCBmaWcud2lkdGg9NS41LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIEZpZyAyZyBwbG90cyAjCkZlYXR1cmVQbG90KFJQTV9BbGxvLCBmZWF0dXJlcyA9IGMoIk5FX3NwZWFybWFuIiksIHB0LnNpemU9MC4yLCAKICAgICAgICAgICAgcmVkdWN0aW9uPSd1bWFwJywgb3JkZXI9VFJVRSkgKyAKICAgIHNjYWxlX2NvbG9yX3ZpcmlkaXMob3B0aW9uPSJyb2NrZXQiLGRpcmVjdGlvbj0tMSkgJiBOb0F4ZXMoKQpgYGAKCiMjIyBWaW9saW4gcGxvdHMgb2YgQXJjaGV0eXBlcyBieSBsZWlkZW4gY2x1c3RlcgojIyMjICoqRXh0LiBEYXRhIEZpZy4gNGYqKgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KVmxuUGxvdCgKICBSUE1fQWxsbywKICBmZWF0dXJlcyA9IGMoIkFfQXJjaGV0eXBlMSIsIkEyX0FyY2hldHlwZTEiLCJOX0FyY2hldHlwZTEiLCJQX0FyY2hldHlwZTEiKSwKICBncm91cC5ieSA9ICJsZWlkZW5fc2NWSV8xLjMiLAogIGNvbHMgPSBteV9jb2xvcnMsCiAgYWxwaGEgPSAwLjcsCiAgbmNvbCA9IDIKKSAmIAogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDgpLCAgICAgICAgICAgICAgICAjIHNtYWxsZXIgeC1heGlzIGxhYmVscwogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplPTApLCAgICAgICAgICAjIGl0YWxpY2l6ZSB0aXRsZXMKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjQpLCAgICAgICAgICAgICAgIyBvcHRpb25hbCBzaXplIHR3ZWFrcwogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCkKICApICYKICBsYWJzKAogICAgeSA9ICJFeHByZXNzaW9uIiwKICAgIHggPSAiQ2x1c3RlciIKICApCgpgYGAKCgojIyMgUGxvdCBTaWduYXR1cmUgU2NvcmVzIGJ5IFBoZW5vdHlwZQpgYGB7cn0KcGhlbm90eXBlcyA8LSBhcy5jaGFyYWN0ZXIodW5pcXVlKFJQTV9BbGxvJFBoZW5vKSkKcGhlbm9fcGFpcnNfbGlzdCA8LSBjb21ibihwaGVub3R5cGVzLCAyLCBzaW1wbGlmeSA9IEZBTFNFKQpgYGAKCiMjIyMgRGVmaW5lIGZ1bmN0aW9uIHRvIHBsb3QgdmlvbGluIHBsb3RzIGJ5IHBoZW5vdHlwZQpgYGB7cn0KcGxvdFZsbkJ5UGhlbiA8LSBmdW5jdGlvbihmZWF0dXJlLCB5bD1jKC0wLjEsMC4zKSwgZm9jdXM9TkEpIHsKICAgIGlmKCFpcy5uYShmb2N1cykpIHsKICAgICAgICBwaGVub19wYWlyc19saXN0IDwtIHBoZW5vX3BhaXJzX2xpc3Rbc2FwcGx5KHBoZW5vX3BhaXJzX2xpc3QsIGZ1bmN0aW9uKHgpIGZvY3VzICVpbiUgeCldCiAgICB9CiAgICAKICAgIHNjYXRlcjo6cGxvdENvbERhdGEoc2NlLCB4ID0gIlBoZW5vIiwgeSA9IGZlYXR1cmUsIGNvbG91cl9ieSA9ICJQaGVubyIpICsgCiAgICAgICAgc2NhbGVfZGlzY3JldGVfbWFudWFsKGFlc3RoZXRpY3MgPSBjKCJjb2xvdXIiLCAiZmlsbCIpLCB2YWx1ZXM9cGhlbm9fY29sKSArCiAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCksIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksICAgIyByb3RhdGUgeC1heGlzIGxhYmVscwogICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksICAgICMgcmVtb3ZlIHBsb3QgdGl0bGUKICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIgICAgICAgICAjIHJlbW92ZSBsZWdlbmQKICAgICAgICApICsgbGFicyh4ID0gIiIsICAgICAgICAgICAgICAgICAgICAgIyBjdXN0b20geC1heGlzIHRpdGxlCiAgICAgICAgICAgICAgICAgeSA9ICJTaWduYXR1cmUgc2NvcmUiICAgICAgICAjIGN1c3RvbSB5LWF4aXMgdGl0bGUKICAgICAgICApICsgeWxpbSh5bFsxXSwgeWxbMl0pICsgCiAgICAgICAgZ2VvbV9ib3hwbG90KGZpbGw9cGhlbm9fY29sLCBhbHBoYT0xLzUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuMiksCiAgICAgICAgICAgICAgICAgICAgIHNpemU9MC4yLCBjb2xvcj0iYmxhY2siLCBub3RjaD1UUlVFLCBub3RjaHdpZHRoPTAuMywgb3V0bGllci5zaGFwZSA9IDIsIG91dGxpZXIuY29sb3VyPU5BKSAjICAgKyAKICAgICAgICAjIHN0YXRfc3VtbWFyeShmdW4gPSBtZWFuLAogICAgICAgICMgICAgICAgICAgICAgIGdlb20gPSAicG9pbnQiLAogICAgICAgICMgICAgICAgICAgICAgIHNoYXBlID0gMTgsCiAgICAgICAgIyAgICAgICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgIyAgICAgICAgICAgICAgY29sb3IgPSAicmVkIiwKICAgICAgICAjICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKyAKICAgICAgICAjIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ3aWxjb3gudGVzdCIsIGxhYmVsID0gInAuc2lnbmlmIiwgc2l6ZT00LCAKICAgICAgICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IFRSVUUsIGNvbXBhcmlzb25zID0gcGhlbm9fcGFpcnNfbGlzdCkKfQpgYGAKCgojIyMjIEZpZyAxbApORSBjb3JyZWxhdGlvbgpgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0yLjUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3RWbG5CeVBoZW4oIk5FX3NwZWFybWFuIiwgeWw9YygtLjc1LCAuOCksIGZvY3VzPSJORSIpCmBgYAoKIyMjIyBGaWcgMW0KU0NMQyBjZWxsIHR5cGUgY29uc2Vuc3VzIHNpZ25hdHVyZSBzY29yZXMKKiBORSBjZWxsCiogVHVmdCBjZWxsCiogQmFzYWwgY2VsbApgYGB7ciBmaWcuaGVpZ2h0PTQsIGZpZy53aWR0aD0zLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwbG90VmxuQnlQaGVuKCJORV9Db25zZW5zdXMxIiwgeWw9YygtMC41LCAxKSkKcGxvdFZsbkJ5UGhlbigiVHVmdF9Db25zZW5zdXMxIiwgeWw9YygtMC4xLCAwLjUpKQpwbG90VmxuQnlQaGVuKCJCYXNhbF9Db25zZW5zdXMxIiwgeWw9YygtMC4xLCAxLjEpKQpgYGAKIyMjIyBGaWcgMW4KVEYgdGFyZ2V0IGdlbmUgc2NvcmVzCiogQVNDTDEgdGFyZ2V0cwoqIE5FVVJPRDEgdGFyZ2V0cwoqIEFUT0gxIHRhcmdldHMKKiBQT1UyRjMgdGFyZ2V0cwoqIFlBUDEgYWN0aXZpdHkgc2NvcmUKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBsb3RWbG5CeVBoZW4oIkFTQ0wxX1RhcmdldHMxIiwgeWw9YygtMC4xLDAuNikpCnBsb3RWbG5CeVBoZW4oIk5FVVJPRDFfVGFyZ2V0czEiLCB5bD1jKC0wLjEsMC4yNSkpCnBsb3RWbG5CeVBoZW4oIkFUT0gxX1RhcmdldHMxIiwgeWw9YygtMC4xLC4zKSkKcGxvdFZsbkJ5UGhlbigiUE9VMkYzX1RhcmdldHMxIiwgeWw9YygtMC4xLCAwLjIyKSkKcGxvdFZsbkJ5UGhlbigiWUFQMV9BY3Rpdml0eV9TY29yZTEiLCB5bD1jKC0wLjEsIDEpKQpgYGAKCg==